home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cool / ge_cool.lha / GE_COOL2.1 / cpp / cpp4.c < prev    next >
C/C++ Source or Header  |  1992-04-13  |  18KB  |  637 lines

  1. /*
  2.  
  3.  
  4.  Copyright (C) 1990 Texas Instruments Incorporated.
  5.  
  6.  Permission is granted to any individual or institution to use, copy, modify,
  7.  and distribute this software, provided that this complete copyright and
  8.  permission notice is maintained, intact, in all copies and supporting
  9.  documentation.
  10.  
  11.  Texas Instruments Incorporated provides this software "as is" without
  12.  express or implied warranty.
  13.  
  14.  
  15.  *                C P P 4 . C
  16.  *        M a c r o  D e f i n i t i o n s
  17.  *
  18.  * Edit History
  19.  * 30-Oct-90    MJF    Fix __LINE__ when in a macro
  20.  * 31-Aug-84    MM    USENET net.sources release
  21.  * 04-Oct-84    MM    __LINE__ and __FILE__ must call ungetstring()
  22.  *            so they work correctly with token concatenation.
  23.  *            Added string formal recognition.
  24.  * 25-Oct-84    MM    "Short-circuit" evaluate #if's so that we
  25.  *            don't print unnecessary error messages for
  26.  *            #if !defined(FOO) && FOO != 0 && 10 / FOO ...
  27.  * 31-Oct-84    ado/MM    Added token concatenation
  28.  *  6-Nov-84    MM    Split off eval stuff
  29.  * 21-Oct-85    RMS    Rename `token' to `tokenbuf'.
  30.  *            In doundef, don't complain if arg already not defined.
  31.  * 20-Apr-90    MJF     Changed redefining of defined variable to a warning
  32.  * 18-May-90    MBN     Conditional compilation for COOL to get "clean" cpp
  33.  * 25-Jun-91    GPD    Fixes to make ## operator expansion ANSI conformant.
  34.  *  5-Sep-91    DLS    Remove previous fixes which cause COOL problems.
  35.  */
  36.  
  37. #include    <stdio.h>
  38. #include    <ctype.h>
  39. #include    "cppdef.h"
  40. #include    "cpp.h"
  41. /*
  42.  * parm[], parmp, and parlist[] are used to store #define() argument
  43.  * lists.  nargs contains the actual number of parameters stored.
  44.  */
  45. static char    parm[NPARMWORK + 1];    /* define param work buffer     */
  46. static char    *parmp;            /* Free space in parm        */
  47. static char    *parlist[LASTPARM];    /* -> start of each parameter    */
  48. static int    nargs;            /* Parameters for this macro    */
  49.  
  50. dodefine()
  51. /*
  52.  * Called from control when a #define is scanned.  This module
  53.  * parses formal parameters and the replacement string.  When
  54.  * the formal parameter name is encountered in the replacement
  55.  * string, it is replaced by a character in the range 128 to
  56.  * 128+NPARAM (this allows up to 32 parameters within the
  57.  * Dec Multinational range).  If cpp is ported to an EBCDIC
  58.  * machine, you will have to make other arrangements.
  59.  *
  60.  * There is some special case code to distinguish
  61.  *    #define foo    bar
  62.  * from    #define foo()    bar
  63.  *
  64.  * Also, we make sure that
  65.  *    #define    foo    foo
  66.  * expands to "foo" but doesn't put cpp into an infinite loop.
  67.  *
  68.  * A warning message is printed if you redefine a symbol to a
  69.  * different text.  I.e,
  70.  *    #define    foo    123
  71.  *    #define foo    123
  72.  * is ok, but
  73.  *    #define foo    123
  74.  *    #define    foo    +123
  75.  * is not.
  76.  *
  77.  * The following subroutines are called from define():
  78.  * checkparm    called when a token is scanned.  It checks through the
  79.  *        array of formal parameters.  If a match is found, the
  80.  *        token is replaced by a control byte which will be used
  81.  *        to locate the parameter when the macro is expanded.
  82.  * textput    puts a string in the macro work area (parm[]), updating
  83.  *        parmp to point to the first free byte in parm[].
  84.  *        textput() tests for work buffer overflow.
  85.  * charput    puts a single character in the macro work area (parm[])
  86.  *        in a manner analogous to textput().
  87.  */
  88. {
  89.     register int        c;
  90.     register DEFBUF        *dp;        /* -> new definition    */
  91.     int            isredefine;    /* TRUE if redefined    */
  92.     char            *old;        /* Remember redefined    */
  93.     extern int        save();        /* Save char in work[]    */
  94.  
  95.     if (type[(c = skipws())] != LET)
  96.         goto bad_define;
  97.     isredefine = FALSE;            /* Set if redefining    */
  98.     if ((dp = lookid(c)) == NULL)        /* If not known now    */
  99.         dp = defendel(tokenbuf, FALSE);    /* Save the name    */
  100.     else {                    /* It's known:        */
  101.         isredefine = TRUE;            /* Remember this fact    */
  102.         old = dp->repl;            /* Remember replacement    */
  103.         dp->repl = NULL;            /* No replacement now    */
  104.     }
  105.     parlist[0] = parmp = parm;        /* Setup parm buffer    */
  106.     if ((c = get()) == '(') {        /* With arguments?    */
  107.         nargs = 0;                /* Init formals counter    */
  108.         do {                /* Collect formal parms    */
  109.         if (nargs >= LASTPARM)
  110.             cfatal("Too many arguments for macro", NULLST);
  111.         else if ((c = skipws()) == ')')
  112.             break;            /* Got them all        */
  113.         else if (type[c] != LET)    /* Bad formal syntax    */
  114.             goto bad_define;
  115.         scanid(c);            /* Get the formal param    */
  116.         parlist[nargs++] = parmp;    /* Save its start    */
  117.         textput(tokenbuf);        /* Save text in parm[]    */
  118.         } while ((c = skipws()) == ',');    /* Get another argument    */
  119.         if (c != ')')            /* Must end at )    */
  120.         goto bad_define;
  121.         c = ' ';                /* Will skip to body    */
  122.     }
  123.     else {
  124.         /*
  125.          * DEF_NOARGS is needed to distinguish between
  126.          * "#define foo" and "#define foo()".
  127.          */
  128.         nargs = DEF_NOARGS;            /* No () parameters    */
  129.     }
  130.     if (type[c] == SPA)            /* At whitespace?    */
  131.         c = skipws();            /* Not any more.    */
  132.     workp = work;                /* Replacement put here    */
  133.     inmacro = TRUE;                /* Keep \<newline> now    */
  134.     while (c != EOF_CHAR && c != '\n') {    /* Compile macro body    */
  135. #if OK_CONCAT
  136.         if (c == '#') {            /* Token concatenation?    */
  137.           if((c = get()) != '#') {
  138.         save('#');            /* Lone #, just save it. */
  139.         if(type[c] == LET) {
  140.           if (checkparm(c, dp))     /* Single # next to parm */
  141.             workp[-2] = MAC_PARM + PAR_MAC;/* Mark next parameter */
  142.           c = get();}  
  143.             continue;}
  144.           while (workp > work && type[(unsigned char)workp[-1]] == SPA)
  145.         --workp;            /* Erase leading spaces    */
  146. /****          save(TOK_SEP); */            /* Stuff a delimiter    */
  147.           c = skipws();            /* Eat whitespace    */
  148.           continue;
  149.         }
  150. #endif    /*  OK_CONCAT  */
  151.         switch (type[c]) {
  152.         case LET:
  153.         checkparm(c, dp);        /* Might be a formal    */
  154.         break;
  155.  
  156.         case DIG:                /* Number in mac. body    */
  157.         case DOT:                /* Maybe a float number    */
  158.         scannumber(c, save);        /* Scan it off        */
  159.         break;
  160.  
  161.         case QUO:                /* String in mac. body    */
  162. #if STRING_FORMAL
  163.         stparmscan(c, dp);        /* Do string magic    */
  164. #else
  165.         scanstring(c, save);
  166. #endif
  167.         break;
  168.  
  169.         case BSH:                /* Backslash        */
  170.         save('\\');
  171.         if ((c = get()) == '\n')
  172.             wrongline = TRUE;
  173.         save(c);
  174.         break;
  175.  
  176.         case SPA:                /* Absorb whitespace    */
  177.         /*
  178.          * Note: the "end of comment" marker is passed on
  179.          * to allow comments to separate tokens.
  180.          */
  181.         if (workp[-1] == ' ')        /* Absorb multiple    */
  182.             break;            /* spaces        */
  183.         else if (c == '\t')
  184.             c = ' ';            /* Normalize tabs    */
  185.         /* Fall through to store character            */
  186.         default:                /* Other character    */
  187.         save(c);
  188.         break;
  189.         }
  190.         c = get();
  191.     }
  192.     inmacro = FALSE;            /* Stop newline hack    */
  193.     unget();                /* For control check    */
  194.     if (workp > work && workp[-1] == ' ')    /* Drop trailing blank    */
  195.         workp--;
  196.     *workp = EOS;                /* Terminate work    */
  197.     dp->repl = savestring(work);        /* Save the string    */
  198.     dp->nargs = nargs;            /* Save arg count    */
  199. #if DEBUG
  200.     if (debug)
  201.         dumpadef("macro definition", dp);
  202. #endif
  203.     if (isredefine) {            /* Error if redefined    */
  204.         if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl))
  205.          || (old == NULL && dp->repl != NULL)
  206.          || (old != NULL && dp->repl == NULL)) {
  207.         cwarn("Redefining defined variable \"%s\"", dp->name);
  208.         }
  209.         if (old != NULL)            /* We don't need the    */
  210.         free(old);            /* old definition now.    */
  211.     }     
  212.     return(0);
  213.  
  214. bad_define:
  215.     cerror("#define syntax error", NULLST);
  216.     inmacro = FALSE;            /* Stop <newline> hack    */
  217. }
  218.  
  219. int
  220. checkparm(c, dp)
  221. register int    c;
  222. DEFBUF        *dp;
  223. /*
  224.  * Replace this param if it's defined, returning TRUE.
  225.  * Note that the macro name is a possible replacement token.
  226.  * We stuff DEF_MAGIC in front of the token
  227.  * which is treated as a LETTER by the token scanner and eaten by
  228.  * the output routine.  This prevents the macro expander from
  229.  * looping if someone writes "#define foo foo".
  230.  */
  231. {
  232.     register int        i;
  233.     register char        *cp;
  234.  
  235.     scanid(c);                /* Get parm to tokenbuf */
  236.     for (i = 0; i < nargs; i++) {        /* For each argument    */
  237.         if (streq(parlist[i], tokenbuf)) {    /* If it's known    */
  238.         save(i + MAC_PARM);            /* Save a magic cookie    */
  239.         return(TRUE);            /* And exit the search    */
  240.         }
  241.     }
  242.     if (streq(dp->name, tokenbuf))        /* Macro name in body?    */
  243.         save(DEF_MAGIC);            /* Save magic marker    */
  244.     for (cp = tokenbuf; *cp != EOS;)    /* And save        */
  245.         save(*cp++);            /* The token itself    */
  246.     return(FALSE);
  247. }
  248.  
  249. #if STRING_FORMAL
  250. stparmscan(delim, dp)
  251. int        delim;
  252. register DEFBUF    *dp;
  253. /*
  254.  * Scan the string (starting with the given delimiter).
  255.  * The token is replaced if it is the only text in this string or
  256.  * character constant.  The algorithm follows checkparm() above.
  257.  * Note that scanstring() has approved of the string.
  258.  */
  259. {
  260.     register int        c;
  261.  
  262.     /*
  263.      * Warning -- this code hasn't been tested for a while.
  264.      * It exists only to preserve compatibility with earlier
  265.      * implementations of cpp.  It is not part of the Draft
  266.      * ANSI Standard C language.
  267.      */
  268.     save(delim);
  269.     instring = TRUE;
  270.     while ((c = get()) != delim
  271.          && c != '\n'
  272.          && c != EOF_CHAR) {
  273.         if (type[c] == LET)            /* Maybe formal parm    */
  274.         checkparm(c, dp);
  275.         else {
  276.         save(c);
  277.         if (c == '\\')
  278.             save(get());
  279.         }
  280.     }
  281.     instring = FALSE;
  282.     if (c != delim)
  283.         cerror("Unterminated string in macro body", NULLST);
  284.     save(c);
  285. }
  286. #endif
  287.  
  288. doundef()
  289. /*
  290.  * Remove the symbol from the defined list.
  291.  * Called from the #control processor.
  292.  */
  293. {
  294.   register int c;
  295.  
  296.   if (type[(c = skipws())] != LET)
  297.     cerror("Illegal #undef argument", NULLST);
  298.   else
  299.     {
  300.       scanid(c);                /* Get name to tokenbuf */
  301.       defendel(tokenbuf, TRUE);
  302.     }
  303. }
  304.  
  305. textput(text)
  306. char        *text;
  307. /*
  308.  * Put the string in the parm[] buffer.
  309.  */
  310. {
  311.     register int    size;
  312.  
  313.     size = strlen(text) + 1;
  314.     if ((parmp + size) >= &parm[NPARMWORK])
  315.         cfatal("Macro work area overflow", NULLST);
  316.     else {
  317.         strcpy(parmp, text);
  318.         parmp += size;
  319.     }
  320. }
  321.  
  322. charput(c)
  323. register int    c;
  324. /*
  325.  * Put the byte in the parm[] buffer.
  326.  */
  327. {
  328.     if (parmp >= &parm[NPARMWORK])
  329.         cfatal("Macro work area overflow", NULLST);
  330.     else {
  331.         *parmp++ = c;
  332.     }
  333. }
  334.  
  335. /*
  336.  *        M a c r o   E x p a n s i o n
  337.  */
  338.  
  339. expand(tokenp)
  340. register DEFBUF    *tokenp;
  341. /*
  342.  * Expand a macro.  Called from the cpp mainline routine (via subroutine
  343.  * macroid()) when a token is found in the symbol table.  It calls
  344.  * expcollect() to parse actual parameters, checking for the correct number.
  345.  * It then creates a "file" containing a single line containing the
  346.  * macro with actual parameters inserted appropriately.  This is
  347.  * "pushed back" onto the input stream.  (When the get() routine runs
  348.  * off the end of the macro line, it will dismiss the macro itself.)
  349.  */
  350. {
  351.     register int        c;
  352.  
  353. #if DEBUG
  354.     if (debug)
  355.         dumpadef("expand entry", tokenp);
  356. #endif    
  357.     /*
  358.      * If no macro is pending, save the name of this macro
  359.      * for an eventual error message.
  360.      */
  361.     if (recursion++ == 0)
  362.         macro = tokenp;
  363.     else if (recursion == RECURSION_LIMIT) {
  364.         cerror("Recursive macro definition of \"%s\"", tokenp->name);
  365.         fprintf(stderr, "(Defined by \"%s\")\n", macro->name);
  366.         if (rec_recover) {
  367.         do {
  368.             c = get();
  369.         } while (infile != NULL && infile->fp == NULL);
  370.         unget();
  371.         recursion = 0;
  372.         return(0);
  373.         }
  374.     }
  375.     /*
  376.      * Here's a macro to expand.
  377.      */
  378.     nargs = 0;                /* Formals counter    */
  379.     parmp = parm;                /* Setup parm buffer    */
  380.     switch (tokenp->nargs) {
  381.     case DEF_BUILTIN:
  382.       (tokenp->expander)(tokenp->repl);    /* Builtin  macros      */
  383.       break;
  384.     default:
  385.         /*
  386.          * Nothing funny about this macro.
  387.          */
  388.         if (tokenp->nargs < 0)
  389.         cfatal("Bug: Illegal __ macro \"%s\"", tokenp->name);
  390.         while ((c = skipws()) == '\n')    /* Look for (, skipping    */
  391.         wrongline = TRUE;        /* spaces and newlines    */
  392.         if (c != '(') {
  393.         /*
  394.          * If the programmer writes
  395.          *    #define foo() ...
  396.          *    ...
  397.          *    foo [no ()]
  398.          * just write foo to the output stream.
  399.          */
  400.         unget();
  401.         cwarn("Macro \"%s\" needs arguments", tokenp->name);
  402.         fputs(tokenp->name, stdout);
  403.         return(0);
  404.         }
  405.         else if (expcollect()) {        /* Collect arguments    */
  406.         if (tokenp->nargs != nargs) {    /* Should be an error?    */
  407.             cwarn("Wrong number of macro arguments for \"%s\"",
  408.             tokenp->name);
  409.         }
  410. #if DEBUG
  411.         if (debug)
  412.             dumpparm("expand");
  413. #endif
  414.         }                /* Collect arguments        */
  415.     case DEF_NOARGS:        /* No parameters just stuffs    */
  416.         expstuff(tokenp);        /* Do actual parameters        */
  417.     }                /* nargs switch            */
  418. }
  419.  
  420. void
  421. expand_line (dp)
  422.   char* dp;
  423. {
  424.   register FILEINFO    *file;
  425.               /* Find bottom level file (the file being compiled) */
  426.   for (file = infile; file != NULL; file = file->parent) {
  427.     if (file->parent == NULL) {
  428.       sprintf(work, "%d", file->line);
  429.       ungetstring(work);
  430.       break;
  431.     }
  432.   }
  433. }
  434.  
  435. void
  436. expand_file (dp)
  437.      char *dp;
  438. {
  439.   register FILEINFO    *file;
  440.               /* Find bottom level file (the file being compiled) */
  441.   for (file = infile; file != NULL; file = file->parent) {
  442.     if (file->parent == NULL) {
  443.       sprintf(work, "\"%s\"", (file->progname != NULL)
  444.           ? file->progname : file->filename);
  445.       ungetstring(work);
  446.       break;
  447.     }
  448.   }
  449. }
  450.  
  451. #ifndef COOL
  452. /* We need this routine here only when we are building a clean, ie. non-COOL
  453.  * preprocessor. For COOL, this function is defined in cpp7.c
  454.  */
  455. FILEINFO*
  456. get_temp_file (bufsize, name)
  457.      int bufsize;
  458.      char* name;
  459. {
  460.   extern FILEINFO    *getfile();
  461.   FILEINFO* file = getfile(bufsize, name);
  462.   infile = file->parent;
  463.   file->parent = NULL;
  464.   line = infile->line;
  465.   return(file);
  466. }
  467. #endif
  468.  
  469. FILE_LOCAL int
  470. expcollect()
  471. /*
  472.  * Collect the actual parameters for this macro.  TRUE if ok.
  473.  */
  474. {
  475.     register int    c;
  476.     register int    paren;            /* For embedded ()'s    */
  477.     extern int    charput();
  478.  
  479.     for (;;) {
  480.         paren = 0;                /* Collect next arg.    */
  481.         while ((c = skipws()) == '\n')    /* Skip over whitespace    */
  482.         wrongline = TRUE;        /* and newlines.    */
  483.         if (c == ')') {            /* At end of all args?    */
  484.         /*
  485.          * Note that there is a guard byte in parm[]
  486.          * so we don't have to check for overflow here.
  487.          */
  488.         *parmp = EOS;            /* Make sure terminated    */
  489.         break;                /* Exit collection loop    */
  490.         }
  491.         else if (nargs >= LASTPARM)
  492.         cfatal("Too many arguments in macro expansion", NULLST);
  493.         parlist[nargs++] = parmp;        /* At start of new arg    */
  494.         for (;; c = cget()) {        /* Collect arg's bytes    */
  495.         if (c == EOF_CHAR) {
  496.             cfatal("end of file within macro argument", NULLST);
  497.             return (FALSE);        /* Sorry.        */
  498.         }
  499.         else if (c == '\\') {        /* Quote next character    */
  500.             charput(c);            /* Save the \ for later    */
  501.             charput(cget());        /* Save the next char.    */
  502.             continue;            /* And go get another    */
  503.         }
  504.         else if (type[c] == QUO) {    /* Start of string?    */
  505.             scanstring(c, charput);    /* Scan it off        */
  506.             continue;            /* Go get next char    */
  507.         }
  508.         else if (c == '(')        /* Worry about balance    */
  509.             paren++;            /* To know about commas    */
  510.         else if (c == ')') {        /* Other side too    */
  511.             if (paren == 0) {        /* At the end?        */
  512.             unget();        /* Look at it later    */
  513.             break;            /* Exit arg getter.    */
  514.             }
  515.             paren--;            /* More to come.    */
  516.         }
  517.         else if (c == ',' && paren == 0) /* Comma delimits args    */
  518.             break;
  519.         else if (c == '\n')        /* Newline inside arg?    */
  520.             wrongline = TRUE;        /* We'll need a #line    */
  521.         else if (c == DEF_MAGIC)        /* skip magic marker    */
  522.             continue;
  523.         charput(c);            /* Store this one    */
  524.         }                    /* Collect an argument    */
  525.         charput(EOS);            /* Terminate argument    */
  526. #if DEBUG
  527.         if (debug)
  528.             printf("parm[%d] = \"%s\"\n", nargs, parlist[nargs - 1]);
  529. #endif
  530.     }                    /* Collect all args.    */
  531.     return (TRUE);                /* Normal return    */
  532. }
  533.  
  534. FILE_LOCAL
  535. expstuff(tokenp)
  536. DEFBUF        *tokenp;        /* Current macro being expanded    */
  537. /*
  538.  * Stuff the macro body, replacing formal parameters by actual parameters.
  539.  */
  540. {
  541.     register int    c;            /* Current character    */
  542.     register char    *inp;            /* -> repl string    */
  543.     register char    *defp;            /* -> macro output buff    */
  544.     int        size;            /* Actual parm. size    */
  545.     char        *defend;        /* -> output buff end    */
  546.     int        string_magic;        /* String formal hack    */
  547.     FILEINFO    *file;                /* Funny #include    */
  548.     extern FILEINFO    *getfile();
  549.     extern FILEINFO    *get_temp_file();
  550.  
  551.     file = getfile(NBUFF, tokenp->name);
  552.     inp = tokenp->repl;            /* -> macro replacement    */
  553.     defp = file->buffer;            /* -> output buffer    */
  554.     defend = defp + (NBUFF - 24);        /* Note its end        */
  555.     if (inp != NULL) {
  556.         while ((c = (*inp++ & 0xFF)) != EOS) {
  557.           if (defp >= defend) {        /* If out of space      */
  558.         FILEINFO* new = get_temp_file(NBUFF, file->filename);
  559.         new->parent = file->parent; /* When new ends read from infile */
  560.         file->parent = new;        /* When file ends read from new   */
  561.         file = new;
  562.         *defp = EOS;
  563.         defp = file->buffer;
  564.         defend = defp + (NBUFF - 24);
  565.           }
  566.  
  567.           if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) {
  568.         string_magic = (c == (MAC_PARM + PAR_MAC));
  569.         if (string_magic) {        /* When quoted parameter */
  570.           c = (*inp++ & 0xFF);
  571.           *defp++ = '\"';
  572.         }
  573.         /*
  574.          * Replace formal parameter by actual parameter string.
  575.          */
  576.         if ((c -= MAC_PARM) < nargs) {
  577.           size = strlen(parlist[c]);
  578.           if ((defp + size + 24) >= defend) {
  579.             *defp = EOS;        /* If out of space */
  580.             defend = defp;
  581.             if (string_magic) inp--; 
  582.             inp--;            /* backup and try again */
  583.             continue;
  584.           }
  585.           if (string_magic) {        /* When quoted parameter */
  586.             char* p = parlist[c];
  587.             for(; (c = *p++) != EOS;) {
  588.               switch (c) {
  589.               case '\"':
  590.               case '\\':
  591.             *defp++ = '\\';
  592.               default:
  593.             *defp++ = c;
  594.               } /* switch */
  595.             } /* for */
  596.             *defp++ = '\"';
  597.           } else {
  598.             strncpy(defp, parlist[c], size);
  599.             defp += size;
  600.           } /* if string_magic */
  601.         } /* if valid parm */
  602.           } /* if parm */
  603.           else
  604.         /* The following was added by GPD to fix ## token concatenation
  605.            but it causes cpp to go into a loop in processing the COOL
  606.            source (Symbol.C) so it was removed.
  607.  
  608.         if (c != DEF_MAGIC)
  609.         */
  610.         *defp++ = c;
  611.         }
  612.       }
  613.     *defp = EOS;
  614. #if DEBUG
  615.     if (debug > 1)
  616.         printf("macroline: \"%s\"\n", file->buffer);
  617. #endif
  618. }
  619.  
  620. #if DEBUG
  621. dumpparm(why)
  622. char        *why;
  623. /*
  624.  * Dump parameter list.
  625.  */
  626. {
  627.     register int    i;
  628.  
  629.     printf("dump of %d parameters (%d bytes total) %s\n",
  630.         nargs, parmp - parm, why);
  631.     for (i = 0; i < nargs; i++) {
  632.         printf("parm[%d] (%d) = \"%s\"\n",
  633.         i + 1, strlen(parlist[i]), parlist[i]);
  634.     }
  635. }
  636. #endif
  637.